package com.xopencode.io.chat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * @author Mcb
 * @date 2022/5/9
 * @apiNote 聊天室服务端
 */
public class ChatServer {
    private ServerSocketChannel serverSocketChannel;
    private Selector selector;
    private static final int PORT = 10086;

    public static void main(String[] args) {
        ChatServer chatServer = new ChatServer();
        chatServer.listening();
    }

    public ChatServer(){
        try {
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(PORT));
            serverSocketChannel.configureBlocking(false);
            selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void listening(){
        try {
            while (true){
                int result = selector.select(3000);
                if (result>0){
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()){
                        SelectionKey selectionKey = iterator.next();
                        //接受操作
                        if (selectionKey.isAcceptable()){
                            SocketChannel socketChannel = serverSocketChannel.accept();
                            socketChannel.configureBlocking(false);
                            //将连接成功的客户端注册到了selector
                            socketChannel.register(selector,SelectionKey.OP_READ);
                            System.out.println(socketChannel.getRemoteAddress()+"连接成功！进入聊天室！");
                        }
                        //通道是否可读
                        if (selectionKey.isReadable()){
                            handleReadData(selectionKey);
                        }
                        iterator.remove();
                    }
                }else {
                    System.out.println("server: waiting.......");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理数据的读取和转发给除了自己之外的客户端
     * @param key
     */
    public void handleReadData(SelectionKey key){
        //客户端通道
        SocketChannel socketChannel = null;

        try {
            //服务器接收来自客户端的消息
            socketChannel = (SocketChannel) key.channel();
            ByteBuffer buffer=ByteBuffer.allocate(1024);
            int len = socketChannel.read(buffer);
            if (len > 0){
                String msg = new String(buffer.array());
                System.out.println("来自客户端的消息是："+msg);
                //转发消息给其他的客户端
                transferMessage(msg,socketChannel);
            }
        } catch (IOException e) {
            try {
                System.out.println(socketChannel.getRemoteAddress()+"离开了聊天室！");
                key.cancel();//取消注册
                socketChannel.close();//关闭通道
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    }


    /**
     *  服务器端转发消息
     * @param msg
     * @param socketChannel
     * @throws IOException
     */
    public void transferMessage(String msg,SocketChannel socketChannel) throws IOException {
        System.out.println("server转发消息ing.......");
        for (SelectionKey key : selector.keys()) {
            SelectableChannel channel = key.channel();
            if (channel instanceof SocketChannel && channel != socketChannel){
                SocketChannel client = (SocketChannel) channel;
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));
                client.write(buffer);
            }
        }
    }

}
